package com.yisin.commun.client;

import java.io.IOException;
import java.io.InputStream;
import java.net.Socket;
import java.util.UUID;

import com.alibaba.fastjson.JSONObject;
import com.yinsin.other.LogHelper;
import com.yinsin.utils.ByteUtils;
import com.yisin.commun.modal.Client;
import com.yisin.commun.modal.Data;
import com.yisin.commun.modal.DataConstant;
import com.yisin.commun.modal.DataPackage;
import com.yisin.commun.modal.DataType;
import com.yisin.commun.modal.HandlerMethod;
import com.yisin.commun.modal.MessageByteData;
import com.yisin.commun.modal.MessageData;
import com.yisin.commun.server.HandleHelper;
import com.yisin.commun.server.TcpPolicyThread;

public class YSSocket {
    private static final LogHelper logger = LogHelper.getLogger(YSSocket.class);

    private Socket socket = null;
    private ISocketEvent event;
    private Client client;
    private Thread socketThread;

    public boolean register(String ip, int port, ISocketEvent event) {
        boolean isright = true;
        try {
            this.socket = new Socket(ip, port);
            
            this.event = event;
            client = new Client(this.socket);
            client.setSid(this.socket.getRemoteSocketAddress().toString());
            String uuid = UUID.randomUUID().toString();
            client.setUuid(uuid.replaceAll("-", ""));

            socketThread = new Thread(new YSSocketThread(this));
            socketThread.start();
            
            this.event.onOpen();
        } catch (IOException e) {
            isright = false;
            logger.error("注册Socket服务失败：" + e.getMessage(), e);
            if(this.event != null){
                this.event.onError(e);
            }
        }
        return isright;
    }

    public void close() throws IOException {
        this.socket.close();
    }

    public ISocketEvent getSocketEvent() {
        return event;
    }

    public Client getClient() {
        return client;
    }

    public Socket getSocket() {
        return socket;
    }

    public Thread getSocketThread() {
        return socketThread;
    }
    
    public boolean sendText(DataType type, String req, Object message){
        return sendMessage(type, req, message);
    }
    
    public boolean sendText(String req, Object message){
        return sendMessage(DataType.TEXT, req, message);
    }
    
    public boolean sendText(MessageData message){
        return sendMessage(DataConstant.REQUEST_MESSAGE, message);
    }
    
    public boolean sendText(String req, MessageData message){
        return sendMessage(req, message);
    }
    
    public boolean sendByte(MessageByteData byteData){
        return sendMessage(DataConstant.REQUEST_MESSAGE, byteData);
    }
    
    public boolean sendByte(String req, MessageByteData byteData){
        return sendMessage(req, byteData);
    }
    
    public boolean sendMessage(String req, MessageData message){
        boolean isok = true;
        try {
            DataPackage dataPackage = new DataPackage(req, message);
            client.send(dataPackage);
        } catch (Exception e) {
            isok = false;
            logger.error("发送消息时异常：" + e.getMessage(), e);
        }
        return isok;
    }
    
    public boolean sendMessage(String req, MessageByteData message){
        boolean isok = true;
        try {
            DataPackage dataPackage = new DataPackage(req, message);
            client.send(dataPackage);
        } catch (Exception e) {
            isok = false;
            logger.error("发送消息时异常：" + e.getMessage(), e);
        }
        return isok;
    }
    
    public boolean sendMessage(DataType type, String req, Object message){
    	boolean isok = true;
        try {
            DataPackage dataPackage = new DataPackage(new Data(type, req, message));
            client.send(dataPackage);
        } catch (Exception e) {
            isok = false;
            logger.error("发送消息时异常：" + e.getMessage(), e);
        }
        return isok;
    }

    class YSSocketThread implements Runnable {
        private Socket socket;
        private Client client;
        private ISocketEvent event;
        private InputStream is;
        private boolean cut = true;

        public YSSocketThread(YSSocket soc) {
            this.client = soc.getClient();
            this.socket = soc.getSocket();
            this.event = soc.getSocketEvent();
        }

        @Override
        public void run() {
            try {
                int i = -1, size = 62;
                if (!this.socket.isClosed()) {
                    this.is = this.socket.getInputStream();
                    byte[] byt = (byte[]) null;
                    byte[] tempByt = null;
                    boolean readFinished = true;
                    String text = null;
                    while (this.cut) {
                        if(!readFinished){
                            try{
                                text = new String(tempByt);
                                JSONObject.parseObject(text);
                                
                                response(tempByt);
                                tempByt = null;
                                readFinished = true;
                            }catch(Exception ex){
                            }
                        }
                        byt = new byte[size];
                        // 堵塞 读取数据
                        i = this.is.read(byt);
                        if (i != -1) {
                            if (i == size) {
                                if (tempByt == null) {
                                    tempByt = byt;
                                } else {
                                    tempByt = ByteUtils.joinByteArray(tempByt, byt);
                                }
                                readFinished = false;
                            } else {
                                if (tempByt == null) {
                                    tempByt = ByteUtils.getByte(byt, i);
                                } else {
                                    tempByt = ByteUtils.joinByteArray(tempByt, ByteUtils.getByte(byt, i));
                                }
                                
                                response(tempByt);
                                tempByt = null;
                                readFinished = true;
                            }
                        } else {
                            this.event.onClose();
                            this.cut = false;
                        }
                    }
                }
            } catch (IOException e) {
                this.event.onClose();
                this.cut = false;
            }

        }
        
        private void response(byte[] tempByt){
            DataPackage pack = null;
            JSONObject json = null;
            byte[] msgByt = null;
            try {
                msgByt = ByteUtils.copyByteArray(tempByt);
                
                String text = new String(msgByt);
                
                TcpPolicyThread.sendPolicyFile(this.socket, text);
                
                json = JSONObject.parseObject(text);
                
                String type = json.getString("type");
                pack = new DataPackage(
                		type.equals("TEXT") ? DataType.TEXT : DataType.BYTE, 
                		json.getString("req"), 
                		json.getString("value"));
                
                if(this.event.filter(pack)){
                	callOnMessage(pack);
                }
                //this.event.onMessage(pack);
            } catch (Exception e) {
                logger.error("接收消息异常：" + client.getSid(), e);
            }
            pack = null;
            json = null;
            msgByt = null;
        }
        
        private void callOnMessage(DataPackage pack){
        	String url = pack.getReq();
        	if(url != null){
        		url = url.replaceAll("/", ".");
        	}
        	HandlerMethod handMethod = HandleHelper.getHandlerMethod(url);
        	if(null != handMethod){
        		try {
    				handMethod.getMethod().invoke(handMethod.getInstance(), new Object[]{
    					client, pack				
    				});
    			} catch (Exception e) {
    				this.event.onMessage(pack);
    			}
        	} else {
        		this.event.onMessage(pack);
        	}
        }

    }
    
    private class _YSSocket {
    	
    }
}
